/* Explorer.java
 * Author: liuex
 * 2007-12-22 ����02:34:23
 *
 * Note: 
 */
package lex.explorer;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.lex.catalog.CatalogEvent;
import org.lex.explorer.Explorer;
import org.lex.explorer.FileInfo;
import org.lex.explorer.StatisticsUtilities;
import org.lex.explorer.StatusBar;
import org.lex.explorer.ToggleSplitPaneAction;
import org.lex.explorer.address.AddressBar;
import org.lex.explorer.directory.DirectoryExplorer;
import org.lex.explorer.file.FileExplorer;
import org.lex.explorer.model.DefaultFileSystemModel;
import org.lex.explorer.model.FileSystemModel;
import org.lex.swing.ContainerFactory;
import org.lex.swing.Swings;
import org.lex.utils.IconCache;
import org.lex.utils.Pair;
import org.lex.utils.SystemProperties;
import org.lex.utils.text.SizeFormat;


public class Explorer extends JPanel implements IExplorer {
	private JToolBar toolBar;
	private JButton upButton;
	private JSplitPane splitPane;
	private JButton refreshButton;
	private JToggleButton treeButton;
	// ==========================
	private AddressBar addressBar = null;
	private DirectoryExplorer directoryExplorer = null;
	private FileExplorer fileExplorer = null;
	private StatusBar statusBar = null;
	// ---------------------------------
	private FileSystemModel fileModel = null;

	public static void main(String[] args) {
		Swings.setUseBoldMetalFont(false);
		Swings.show(new Explorer(new File("i:")), false);
	}

	public Explorer() {
		this(SystemProperties.userHome());
	}

	public Explorer(String directory) {
		this(new File(directory));
	}

	public Explorer(File directory) {
		this(new DefaultFileSystemModel(directory));
	}

	public Explorer(FileSystemModel model) {
		this.setFileModel(model);
		// initialize() depends on getFileModel()
		this.initialize();
		this.hookActionListeners();
		this.updateStatusBar();
	}

	public FileSystemModel getFileModel() {
		return this.fileModel;
	}

	public void setFileModel(FileSystemModel model) {
		if (null != this.fileModel)
			this.fileModel.removeCatalogListener(this);
		this.fileModel = model;
		this.fileModel.addCatalogListener(this);
		this.getAddressBar().setFileModel(model);
		this.getFileExplorer().setFileModel(model);
	}

	public void catalogChanged(CatalogEvent e) {
		this.updateStatusBar();
	}

	public File getDirectory() {
		return this.fileModel.getCatalog().getFile();
	}

	public void setDirectory(File dir) {
		if (null == dir)
			return;
		this.getFileModel().setCatalog(FileInfo.get(this.getFileModel().getFileView(), dir));
	}

	public AddressBar getAddressBar() {
		if (this.addressBar == null)
			this.addressBar = new AddressBar(this.getFileModel());
		return addressBar;
	}

	public DirectoryExplorer getDirectoryExplorer() {
		if (directoryExplorer == null)
			directoryExplorer = new DirectoryExplorer(this.getFileModel().getCatalog().getFile());
		return directoryExplorer;
	}

	public FileExplorer getFileExplorer() {
		if (fileExplorer == null) {
			fileExplorer = new FileExplorer(this.getFileModel());
		}
		return fileExplorer;
	}

	public void setSplitLocation(int location) {
		this.getSplitPane().setDividerLocation(location);
	}

	private JToggleButton getTreeButton() {
		if (treeButton == null) {
			treeButton = new JToggleButton(new ToggleSplitPaneAction(getSplitPane()));
		}
		return treeButton;
	}

	private JButton getUpButton() {
		if (upButton == null) {
			upButton = new JButton();
			upButton.setToolTipText("Go Up");
			upButton.setIcon(IconCache.getIcon(IconCache.GoUp));
			upButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					File parent = getDirectory().getParentFile();
					if (null != parent)
						setDirectory(parent);
				}
			});
		}
		return upButton;
	}

	private JButton getRefreshButton() {
		if (refreshButton == null) {
			refreshButton = new JButton();
			refreshButton.setToolTipText("Refresh");
			refreshButton.setIcon(IconCache.getIcon(IconCache.Refresh));
			refreshButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					getFileModel().reload();
				}
			});
		}
		return refreshButton;
	}

	private void updateStatusBar()
	{
		new SwingWorker<Void, Void>(){
			@Override
			protected Void doInBackground() throws Exception
			{
				Pair<String, String> p = StatisticsUtilities
					.generateFileStatistics( getDirectory() );
				getStatusBar().setInformation( p.first() );
				getStatusBar().setSize( p.second() );
				return null;
			}
		}.execute();
	}

	private void initialize() {
		BorderLayout thisLayout = new BorderLayout();
		this.setLayout(thisLayout);
		this.setPreferredSize(new java.awt.Dimension(454, 337));
		this.add(getToolBar(), BorderLayout.NORTH);
		this.add(getSplitPane(), BorderLayout.CENTER);
		this.add(getStatusBar(), BorderLayout.SOUTH);
	}

	private void hookActionListeners()
	{
		// when table selection changed, update status bar
		this.getFileExplorer().getSelectionModel().addListSelectionListener(
			new ListSelectionListener(){
				@Override
				public void valueChanged( ListSelectionEvent e )
				{
					File[] files = getFileExplorer().getSelectedFiles();
					if( null == files || 0 == files.length )
						return;
					Pair<Integer, Long> p = StatisticsUtilities.getFileStatistics( files );
					StringBuilder buf = new StringBuilder();
					buf.append( files.length ).append( " objects selected ( " );
					buf.append( p.first() ).append( " files, " );
					buf.append( files.length - p.first() ).append( " folders )" );
					getStatusBar().setInformation( buf.toString() );
					buf.setLength( 0 );
					buf.append( SizeFormat.autoFormat( p.second() ) ).append( 'B' );
					getStatusBar().setSize( buf.toString() );
				}
			} );
	}

	private JToolBar getToolBar() {
		if (toolBar == null) {
			toolBar = new JToolBar();
			toolBar.add(getTreeButton());
			toolBar.add(getUpButton());
			toolBar.add(getRefreshButton());
			toolBar.addSeparator();
			toolBar.add(this.getAddressBar());
		}
		return toolBar;
	}

	private JSplitPane getSplitPane() {
		if (splitPane == null) {
			splitPane = ContainerFactory.createBorderlessSplitPane();
			splitPane.setName(getClass().getName() + ".splitPane");
			splitPane.setResizeWeight(0.3);
			splitPane.setDividerSize(5);
			splitPane.add(getDirectoryExplorer(), JSplitPane.LEFT);
			splitPane.add(new JScrollPane(getFileExplorer()), JSplitPane.RIGHT);
		}
		return splitPane;
	}

	private StatusBar getStatusBar() {
		if (null == statusBar)
			statusBar = new StatusBar();
		return statusBar;
	}
}
